package io.plus.user_interface.io.common;


import drds.common.$;
import io.plus.client.ClientConfiguration;
import io.plus.interactive.AsynchronousSocketChannelContext;
import io.plus.interactive.Configuration;
import io.plus.interactive.Io;
import io.plus.user_interface.io.common.listener.BindGroupListener;
import io.plus.user_interface.io.common.packet.Client;
import io.plus.user_interface.io.common.packet.User;
import io.plus.user_interface.io.common.protocol.PacketImpl;
import io.plus.user_interface.io.common.utils.ImKit;
import io.plus.utils.lock.ReadWriteLockSet;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;

@Slf4j
@Data
public class io {

    public static UserConfiguration userConfiguration = null;


    /**
     * 绑定群组;
     *
     * @param asynchronousSocketChannelContext
     * @param group
     */
    public static void bindGroup(AsynchronousSocketChannelContext asynchronousSocketChannelContext, String group) {
        bindGroup(asynchronousSocketChannelContext, group, null);
    }

    /**
     * 绑定群组,同时可传递监听器执行回调函数
     *
     * @param asynchronousSocketChannelContext
     * @param group
     * @param bindGroupListener(绑定监听器回调)
     */
    public static void bindGroup(AsynchronousSocketChannelContext asynchronousSocketChannelContext, String group, BindGroupListener bindGroupListener) {
        Io.bindGroup(asynchronousSocketChannelContext, group);
        if (bindGroupListener != null) {
            try {
                bindGroupListener.onAfterGroupBind(asynchronousSocketChannelContext, group);
            } catch (Exception e) {
                log.error(e.toString(), e);
            }
        }
    }

    /**
     * 绑定用户;
     *
     * @param asynchronousSocketChannelContext
     * @param userId
     */
    public static void bindUser(AsynchronousSocketChannelContext asynchronousSocketChannelContext, String userId) {
        bindUser(asynchronousSocketChannelContext, userId, null);
    }

    /**
     * 绑定用户,同时可传递监听器执行回调函数
     *
     * @param asynchronousSocketChannelContext
     * @param userId
     * @param bindListener(绑定监听器回调)
     */
    public static void bindUser(AsynchronousSocketChannelContext asynchronousSocketChannelContext, String userId, BindGroupListener bindListener) {
        Io.bindUser(asynchronousSocketChannelContext, userId);
        if (bindListener != null) {
            try {
                bindListener.onAfterUserBind(asynchronousSocketChannelContext, userId);
            } catch (Exception e) {
                log.error(e.toString(), e);
            }
        }
    }

    /**
     * 阻塞发送（确认把packet发送到对端后再返回）
     *
     * @param asynchronousSocketChannelContext
     * @param packet
     * @return
     */
    public static boolean bSend(AsynchronousSocketChannelContext asynchronousSocketChannelContext, PacketImpl packet) {
        PacketImpl respPacket = initAndSetConvertPacket(asynchronousSocketChannelContext, packet);
        if (respPacket == null) {
            return false;
        }
        return Io.bSend(asynchronousSocketChannelContext, respPacket);
    }

    /**
     * 功能描述：[获取所有在线用户] ： 创建时间: 2017年9月18日 下午4:31:42
     *
     * @return
     */
    public static List<User> getAllOnlineUser() {
        List<User> users = new ArrayList<User>();
        ReadWriteLockSet<AsynchronousSocketChannelContext> onlineChannels = Io.getAllConnectedsChannelContexts((ClientConfiguration) userConfiguration.getConfiguration());
        if (onlineChannels == null) {
            return users;
        }
        ReadLock readLock = onlineChannels.getLock().readLock();
        readLock.lock();
        try {
            Set<AsynchronousSocketChannelContext> userChannels = onlineChannels.getObject();
            for (AsynchronousSocketChannelContext asynchronousSocketChannelContext : userChannels) {
                SessionContext sessionContext = (SessionContext) asynchronousSocketChannelContext.getAttribute();
                if (sessionContext != null) {
                    Client client = sessionContext.getClient();
                    if (client != null && client.getUser() != null) {
                        User user = ImKit.copyUserWithoutUsers(client.getUser());
                        users.add(user);
                    }
                }
            }
        } finally {
            readLock.unlock();
        }
        return users;
    }

    /**
     * 功能描述：[获取所有用户(在线+离线)] ： 创建时间: 2017年9月18日 下午4:31:54
     *
     * @return
     */
    public static List<User> getAllUser() {
        List<User> users = new ArrayList<User>();
        ReadWriteLockSet<AsynchronousSocketChannelContext> allChannels = Io.getAllChannelContexts(userConfiguration.getConfiguration());
        if (allChannels == null) {
            return users;
        }
        ReadLock readLock = allChannels.getLock().readLock();
        readLock.lock();
        try {
            Set<AsynchronousSocketChannelContext> userChannels = allChannels.getObject();
            if ($.isNotNullAndHasElement(userChannels)) {
                return users;
            }
            for (AsynchronousSocketChannelContext asynchronousSocketChannelContext : userChannels) {
                SessionContext sessionContext = (SessionContext) asynchronousSocketChannelContext.getAttribute();
                Client client = sessionContext.getClient();
                if (client != null && client.getUser() != null) {
                    User user = ImKit.copyUserWithoutUsers(client.getUser());
                    users.add(user);
                }
            }
        } finally {
            readLock.unlock();
        }
        return users;
    }

    /**
     * 根据群组获取所有用户;
     *
     * @param group
     * @return
     */
    public static List<User> getAllUserByGroup(String group) {
        ReadWriteLockSet<AsynchronousSocketChannelContext> withLockChannels = Io.getChannelContextsByGroup(userConfiguration.getConfiguration(), group);
        if (withLockChannels == null) {
            return null;
        }
        ReadLock readLock = withLockChannels.getLock().readLock();
        readLock.lock();
        try {
            Set<AsynchronousSocketChannelContext> channels = withLockChannels.getObject();
            if ($.isNotNullAndHasElement(channels)) {
                return null;
            }
            List<User> users = new ArrayList<User>();
            Map<String, User> userMaps = new HashMap<String, User>();
            for (AsynchronousSocketChannelContext asynchronousSocketChannelContext : channels) {
                String userId = asynchronousSocketChannelContext.userId;
                User user = getUser(userId);
                if (user != null && userMaps.get(userId) == null) {
                    userMaps.put(userId, user);
                    users.add(user);
                }
            }
            userMaps = null;
            return users;
        } finally {
            readLock.unlock();
        }
    }

    /**
     * 功能描述：[根据用户ID获取当前用户所在通道集合] ： 创建时间: 2017年9月18日 下午4:34:39
     *
     * @param userId
     * @return
     */
    public static ReadWriteLockSet<AsynchronousSocketChannelContext> getChannelContextsByUserId(String userId) {
        ReadWriteLockSet<AsynchronousSocketChannelContext> channelContexts = Io.getChannelContextsByUserid(userConfiguration.getConfiguration(),
                userId);
        return channelContexts;
    }

    /**
     * 功能描述：[根据用户ID获取当前用户] ： 创建时间: 2017年9月18日 下午4:34:39
     *
     * @param userId
     * @return
     */
    public static User getUser(String userId) {
        ReadWriteLockSet<AsynchronousSocketChannelContext> userChannelContexts = io.getChannelContextsByUserId(userId);
        if (Objects.isNull(userChannelContexts)) {
            return null;
        }
        ReadLock readLock = userChannelContexts.getLock().readLock();
        readLock.lock();
        try {
            Set<AsynchronousSocketChannelContext> userChannels = userChannelContexts.getObject();
            if ($.isNotNullAndHasElement(userChannels)) {
                return null;
            }
            User user = null;
            for (AsynchronousSocketChannelContext asynchronousSocketChannelContext : userChannels) {
                SessionContext sessionContext = (SessionContext) asynchronousSocketChannelContext.getAttribute();
                Client client = sessionContext.getClient();
                user = client.getUser();
                if (user != null) {
                    return user;
                }
            }
            return user;
        } finally {
            readLock.unlock();
        }
    }

    /**
     * 转换协议包同时设置Packet包信息;
     *
     * @param asynchronousSocketChannelContext
     * @param packet
     * @return
     */
    private static PacketImpl initAndSetConvertPacket(AsynchronousSocketChannelContext asynchronousSocketChannelContext, PacketImpl packet) {
        if (asynchronousSocketChannelContext == null) {
            return null;
        }
        PacketImpl respPacket = ImKit.convertResponsepPacket(packet, packet.getCommand(), asynchronousSocketChannelContext);
        if (respPacket == null) {
            log.error("转换协议包为空,请检查协议！");
            return null;
        }
        respPacket.setSynSeq(packet.getSynSeq());
        if (userConfiguration == null) {
            //userConfiguration = new DefaultImConfigBuilder().setClientConfiguration(clientChannelContext.getClientConfiguration()).build();
        }
        return respPacket;
    }

    /**
     * 移除指定channel, 和close方法一样，只不过不再进行重连等维护性的操作
     *
     * @param asynchronousSocketChannelContext
     * @param remark
     */
    public static void remove(AsynchronousSocketChannelContext asynchronousSocketChannelContext, String remark) {
        Io.remove(asynchronousSocketChannelContext, remark);
    }

    /**
     * 移除用户, 和close方法一样，只不过不再进行重连等维护性的操作
     *
     * @param userId
     * @param remark
     */
    public static void remove(String userId, String remark) {
        ReadWriteLockSet<AsynchronousSocketChannelContext> userChannelContexts = getChannelContextsByUserId(userId);
        if (userChannelContexts != null && userChannelContexts.size() > 0) {
            ReadLock readLock = userChannelContexts.getLock().readLock();
            readLock.lock();
            try {
                Set<AsynchronousSocketChannelContext> channels = userChannelContexts.getObject();
                for (AsynchronousSocketChannelContext asynchronousSocketChannelContext : channels) {
                    remove(asynchronousSocketChannelContext, remark);
                }
            } finally {
                readLock.unlock();
            }
        }
    }

    /**
     * 发送到指定通道;
     *
     * @param asynchronousSocketChannelContext
     * @param packet
     */
    public static boolean send(AsynchronousSocketChannelContext asynchronousSocketChannelContext, PacketImpl packet) {
        PacketImpl respPacket = initAndSetConvertPacket(asynchronousSocketChannelContext, packet);
        if (respPacket == null) {
            return false;
        }
        return Io.send(asynchronousSocketChannelContext, respPacket);
    }

    /**
     * 功能描述：[发送到群组(所有不同协议端)] ： 创建时间: 2017年9月21日 下午3:26:57
     */
    public static void sendToGroup(String groupId, PacketImpl packet) {
        if (packet.getBody() == null) {
            return;
        }
        ReadWriteLockSet<AsynchronousSocketChannelContext> withLockChannels = Io.getChannelContextsByGroup(userConfiguration.getConfiguration(),
                groupId);
        if (withLockChannels == null) {

            return;
        }
        ReadLock readLock = withLockChannels.getLock().readLock();
        readLock.lock();
        try {
            Set<AsynchronousSocketChannelContext> channels = withLockChannels.getObject();
            if ($.isNotNullAndHasElement(channels)) {
                for (AsynchronousSocketChannelContext asynchronousSocketChannelContext : channels) {
                    send(asynchronousSocketChannelContext, packet);
                }
            }
        } finally {
            readLock.unlock();

        }
    }

    /**
     * 发送到指定ip对应的集合
     *
     * @param groupContext
     * @param ip
     * @param packet
     */
/*    public static void sendToIp(Configuration groupContext, String ip, PacketImpl packet) {
        sendToIp(groupContext, ip, packet);
    }*/
    public static void sendToIp(Configuration groupContext, String ip, PacketImpl packet) {
        sendToIp(groupContext, ip, packet, false);
    }

    private static Boolean sendToIp(Configuration groupContext, String ip, PacketImpl packet, boolean isBlock) {
        try {
            ReadWriteLockSet<AsynchronousSocketChannelContext> setWithLock = groupContext.ips.getChannelContextSet(groupContext, ip);
            if (setWithLock == null) {
                log.info("{}, 没有ip为[{}]的对端", groupContext.getName(), ip);
                return false;
            } else {
                Boolean ret = sendToSet(groupContext, setWithLock, packet, isBlock);
                return ret;
            }

        } finally {

        }
    }

    public static Boolean sendToSet(Configuration configuration, ReadWriteLockSet<AsynchronousSocketChannelContext> setWithLock, PacketImpl packet, boolean isBlock) {
        Lock lock = setWithLock.getLock().readLock();
        lock.lock();
        try {
            Set<AsynchronousSocketChannelContext> sets = setWithLock.getObject();
            for (AsynchronousSocketChannelContext asynchronousSocketChannelContext : sets) {
                ReadWriteLockSet<AsynchronousSocketChannelContext> convertSet = new ReadWriteLockSet<AsynchronousSocketChannelContext>(new HashSet<AsynchronousSocketChannelContext>());
                convertSet.add(asynchronousSocketChannelContext);
                PacketImpl resPacket = ImKit.convertResponsepPacket(packet, packet.getCommand(), asynchronousSocketChannelContext);
                Io.sendToSet(configuration, convertSet, resPacket);
            }
        } finally {
            lock.unlock();
        }
        return true;
    }

    /**
     * 发送到指定用户;
     *
     * @param userId
     * @param packet
     */
    public static void sendToUser(String userId, PacketImpl packet) {
        if ($.isNullOrEmpty(userId)) {
            return;
        }
        ReadWriteLockSet<AsynchronousSocketChannelContext> toChannelContexts = getChannelContextsByUserId(userId);
        if (toChannelContexts == null || toChannelContexts.size() < 1) {

            return;
        }
        ReadLock readLock = toChannelContexts.getLock().readLock();
        readLock.lock();
        try {
            Set<AsynchronousSocketChannelContext> set = toChannelContexts.getObject();
            for (AsynchronousSocketChannelContext asynchronousSocketChannelContext : set) {
                send(asynchronousSocketChannelContext, packet);
            }
        } finally {
            readLock.unlock();

        }
    }

    /**
     * 与指定群组解除绑定
     *
     * @param userId
     * @param group
     */
    public static void unbindGroup(String userId, String group) {
        unbindGroup(userId, group, null);
    }

    /**
     * 与指定群组解除绑定,同时可传递监听器执行回调函数
     *
     * @param userId
     * @param group
     * @param bindListener(解绑定监听器回调)
     */
    public static void unbindGroup(String userId, String group, BindGroupListener bindListener) {
        ReadWriteLockSet<AsynchronousSocketChannelContext> userChannelContexts = io.getChannelContextsByUserId(userId);
        if (userChannelContexts == null || userChannelContexts.size() == 0) {
            return;
        }
        ReadLock readLock = userChannelContexts.getLock().readLock();
        readLock.lock();
        try {
            Set<AsynchronousSocketChannelContext> channels = userChannelContexts.getObject();
            for (AsynchronousSocketChannelContext asynchronousSocketChannelContext : channels) {
                Io.unbindGroup(group, asynchronousSocketChannelContext);
                if (bindListener != null) {
                    try {
                        bindListener.onAfterGroupUnbind(asynchronousSocketChannelContext, group);
                    } catch (Exception e) {
                        log.error(e.toString(), e);
                    }
                }
            }
        } finally {
            readLock.unlock();
        }
    }

    /**
     * 解绑用户
     *
     * @param userId
     */
    public static void unbindUser(String userId) {
        unbindUser(userId, null);
    }

    /**
     * 解除绑定用户,同时可传递监听器执行回调函数
     *
     * @param userId
     * @param bindListener(解绑定监听器回调)
     */
    public static void unbindUser(String userId, BindGroupListener bindListener) {
        Io.unbindUser(userConfiguration.getConfiguration(), userId);
        if (bindListener != null) {
            try {
                ReadWriteLockSet<AsynchronousSocketChannelContext> userChannelContexts = io.getChannelContextsByUserId(userId);
                if (userChannelContexts == null || userChannelContexts.size() == 0) {
                    return;
                }
                ReadLock readLock = userChannelContexts.getLock().readLock();
                readLock.lock();
                try {
                    Set<AsynchronousSocketChannelContext> channels = userChannelContexts.getObject();
                    for (AsynchronousSocketChannelContext asynchronousSocketChannelContext : channels) {
                        bindListener.onAfterUserBind(asynchronousSocketChannelContext, userId);
                    }
                } finally {
                    readLock.unlock();
                }
            } catch (Exception e) {
                log.error(e.toString(), e);
            }
        }
    }
}
